# Organisation management

> Supacharger installs an optional, private organisation backend in every aligned application. Set `ORGANISATIONS.ENABLED` to expose product routes; disabling the feature leaves the schema installed but dormant.

# Organisation management

Supacharger installs an optional, private organisation backend in every aligned application. Set `ORGANISATIONS.ENABLED` to expose product routes; disabling the feature leaves the schema installed but dormant.

## Data and roles

The reusable contract contains organisations, `owner`/`admin`/`member` memberships, hashed invitations, reviewable access requests, versioned per-session context, and a private media bucket. Owners and admins manage the organisation. The last owner cannot be removed or demoted.

Organisation creation also creates or synchronises the organisation billing subject. Membership removal and role changes invalidate session contexts that are no longer valid.

## Authenticated RPC

Call `api.organisations(input_payload)` with a verified Supabase access token. The RPC derives the current user, Auth email, and `session_id`; never send those values in the payload.

Supported actions are:

- discovery and context: `list`, `handle.available`, `create`, `switch`, and `read`;
- organisation settings: `update`;
- team management: `members.list`, `members.add`, `members.updateRole`, and `members.remove`;
- invitations: `invites.list`, `invites.create`, `invites.accept`, and `invites.revoke`; and
- access review: `access.request`, `access.list`, `access.approve`, and `access.reject`.

The Bruno request in `docs/bruno/supacharger-rpc/organisations.bru` documents the payload fields. Context-changing results include `requiresSessionRefresh`; refresh the browser session before relying on active-organisation claims.

## Handles, invitations, and access requests

Handles are normalised to lowercase route-safe values. `handle.available` returns false for invalid values, existing organisations, and reserved application routes such as `account`, `api`, `auth`, `pricing`, and `settings`.

Invitation creation returns the raw token once and stores only its SHA-256 hash. Tokens expire, are revocable and single use, and acceptance requires the signed-in Auth email to match the normalised recipient email.

`access.request` is available only when the organisation's access policy is `request`. It creates a pending request; it never grants membership. An owner or admin must approve or reject it.

## Organisation media

The private `organisation-logos` bucket accepts JPEG, PNG, WebP, and GIF files up to 5 MB. Store objects under the organisation UUID. Members can read their organisation's objects, while owners and admins control writes. Persist object paths, not signed URLs.

## Specdrive compatibility

Specdrive remains a semantic consumer because its product schema and licensed presentation predate the Core layout. Its forward migration preserves product-only organisation actions and maps canonical `member` to the existing `contributor` value. Core does not adopt that product-specific role name, usage reporting, agent licensing, or licensed UI.

## Managed routes and interface

When `ORGANISATIONS.ENABLED` is true, the account navigation exposes `/account/organisation`. The managed chooser lists memberships and active context, creates organisations after a handle-availability check, switches context, accepts one-time invitation links, and submits reviewed access requests. Context selection and invitation acceptance refresh the Supabase session before navigation so the next request receives current organisation claims.

Root-handle mode exposes:

- `/{handle}/settings` for name, handle, bio, colour, access policy, logo, and header image;
- `/{handle}/settings/team` for roster, roles, invitations, and access review; and
- `/{handle}/settings/billing` when organisation billing is enabled.

The interface includes keyboard-visible controls, mobile layouts, disabled/busy feedback, empty states, safe errors, and semantic `sc-organisation-*` and shared `sc-control-*` class hooks. If organisations are disabled, the routes return a controlled not-found response and the navigation item is absent.

```text
/account/organisation
  └─ switch/create/accept/request → refresh session → /{handle}/settings
       ├─ /team
       └─ /billing → /billing/portal
```

Use the canonical option shape while keeping values product-owned:

```ts
ORGANISATIONS: {
  ENABLED: false,
  AUTHENTICATION_HANDLE: 'disabled',
  CHOOSER_PATH: '/account/organisation',
  ROUTE_MODE: 'root-handle',
  PROFILE_MEDIA: true,
},
BILLING: {
  ACCOUNT_SUBJECTS: {
    PERSONAL: true,
    ORGANISATION: false,
  },
},
```

## Product profile extensions

The managed profile form owns `FormProvider`, canonical validation, dirty state, and save feedback. Add product fields in `src/supacharger.adapters/organisations/profile-fields.tsx` with `useFormContext()`. Define the matching JSON-serialisable schema, initial-value loader, and mutation in `profile-extension.ts`.

Core owns the `/account/organisation` and `/{handle}/settings` public routes. Do not leave product `page.tsx` files for those same URLs in another route group: Next.js treats route groups as URL-transparent and rejects the duplicate pages during a production build. Use the developer-owned organisation adapters instead:

- `pages.tsx` can preserve product chooser, team, or billing behaviour and register product-only settings sections;
- `navigation.ts` registers links for those extra sections using unique kebab-case IDs that do not replace `profile`, `team`, or `billing`;
- `chrome.tsx` wraps managed settings in the product application chrome and may enforce the product's stronger access boundary; and
- `src/styles/supacharger-organisations.css` styles the managed semantic classes without editing CLI-managed markup.

The CLI installs missing starter adapters once and preserves established product implementations on later updates.

The server parses both canonical and extension values with Zod before calling the database. It invokes extension persistence only after the canonical owner/admin update succeeds. Product code cannot weaken role checks, handle validation, or organisation Storage paths.

Style the complete shared surface through project tokens and its stable semantic hooks in `src/styles/supacharger-organisations.css`. The CLI installs this developer-owned starter when absent and preserves it thereafter. Keep it unlayered so it can override Tailwind-layer defaults; do not edit managed route/components or copy Specdrive's licensed Untitled UI implementation into Core.

## Upgrade and troubleshooting

Run `supacharger coreupdate --plan` before updating. The plan lists the managed routes/tests, missing developer adapter starters, disabled-safe config additions, English catalogue additions, and the forward organisation migration. An application with a reviewed adapted migration under a different immutable name must declare it in `.supacharger/migration-aliases.json`.

After updating, run `supacharger doctor`. A failure normally names an actionable state: two route-group pages resolve to the same public URL; an obsolete `/organisation` or `/auth/*` page still exists; account/organisation config is incomplete; the managed routes/tests or adapter starters are missing; or a migration alias points to a file that does not exist. A disabled organisation feature returning not found is expected and is not a failed installation.

## Specdrive route transition

Specdrive uses the Core-owned route tree and shell. Its authorised chooser, team and billing behaviour, application chrome, usage page, and agent-licence page remain developer-owned adapter implementations. Its licensed presentation stays in Specdrive's developer CSS and components and is not redistributed through the open-source Core.
